package com.wctj.api.business.cmb.service.handle;

import com.wctj.api.base.Result;
import com.wctj.api.base.enums.ApiCode;
import com.wctj.api.base.enums.EventTypeEnums;
import com.wctj.api.base.exception.CustomException;
import com.wctj.api.base.utils.HttpClientUtil;
import com.wctj.api.base.utils.JacksonUtil;
import com.wctj.api.base.utils.JsonUtils;
import com.wctj.api.base.utils.TimeUtils;
import com.wctj.api.business.cmb.enums.CmbPayStatusEnums;
import com.wctj.api.business.common.component.AsyncTransactionalEvent;
import com.wctj.api.business.common.dto.DdwxPaymentCfgInfoDTO;
import com.wctj.api.business.common.dto.DdwxPaymentRecordDTO;
import com.wctj.api.business.common.service.DdwxPaymentCfgInfoService;
import com.wctj.api.business.common.service.DdwxPaymentRecordService;
import com.wctj.api.business.common.service.handler.CmbAbstractEventTypeResponse;
import com.wctj.api.infra.common.bean.NoticeParams;
import com.wctj.api.infra.common.bean.NoticeRequest;
import com.wctj.api.infra.common.util.IOUtils;
import com.wctj.api.infra.web.support.HttpRequestNoticeParams;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 招行-WITHDRAWAL event type 支付回调响应模式处理
 */
@Slf4j
@Service
public class CmbYQN03010EventTypeResponse extends CmbAbstractEventTypeResponse {
    @Resource
    private DdwxPaymentRecordService ddwxPaymentRecordService;
    @Resource
    private DdwxPaymentCfgInfoService ddwxPaymentCfgInfoService;
    @Value("${paysystem.cmb.phpCallbackBizCode:60000}")
    private String phpCallbackBizCode;
    @Resource
    private ApplicationContext applicationContext;


    public String getPayOrderNum(NoticeParams noticeParams) {
        //这里是 代发结果通知消息  提前校验是否有对应流水记录已生成  已生成不再新增记录
        //取一个唯一标识
        /**
         * notdat={"msgdat":{"agcInfo":{"yurref":"202409241110002","sucamt":"5.5"}},"msgtyp":"FINS"}
         */
        String yurref = "";
        log.info(noticeParams.getBodyStr());
        //JSONObject notdatObj = (JSONObject) JacksonUtil.parse(noticeParams.getBodyStr(),Map.class).get("notdat");
        JSONObject notdatObj =  JsonUtils.convertValue(noticeParams.getBody().get("notdat"), JSONObject.class);
        if (notdatObj != null) {
            JSONObject msgdatOBj = notdatObj.optJSONObject("msgdat");
            if (msgdatOBj != null) {
                JSONObject agcInfoOBj = msgdatOBj.optJSONObject("agcInfo");
                if (agcInfoOBj != null) {
                    yurref = agcInfoOBj.optString("yurref");
                }
            }
        }
        return yurref;
    }

    @Override
    public NoticeParams getNoticeParams(NoticeRequest request) {
        NoticeParams noticeParams = new NoticeParams();
        try (InputStream is = request.getInputStream()) {
            String body = IOUtils.toString(is);
            noticeParams.setBodyStr(body);
            noticeParams.setBody(JacksonUtil.parse(body,Map.class));
        } catch (IOException e) {
            throw new CustomException(ApiCode.PAY_CALLBACK_PARAM_ERROR, e);
        }
        Map<String, List<String>> headers = new HashMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String name = headerNames.nextElement();
            headers.put(name, Collections.list(request.getHeaders(name)));
        }
        noticeParams.setHeaders(headers);
        return noticeParams;
    }

    @Override
    public String businessHandle(HttpRequestNoticeParams requestNoticeParam) {
        return "";
    }

    @Override
    public String businessHandle(NoticeParams noticeParams) {
        // 提现消息通知 更新对应记录状态
        String payOrderNum = getPayOrderNum(noticeParams);
        // 异常事件处理
        applicationContext.publishEvent(new AsyncTransactionalEvent(this, "CmbYQN03010EventTypeResponse:" + Thread.currentThread().getId(),
                () -> {
                    try {
                        payBack(noticeParams, payOrderNum);
                    } catch (Exception e) {
                        log.error("支付分发失败", e);
                    }
                }));

        return noticeParams.getBodyStr();
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void payBack(NoticeParams noticeParams, String payOrderNum) {
        log.info("cmb payBack param：{}", noticeParams.getBodyStr());
        DdwxPaymentRecordDTO recordDTO = ddwxPaymentRecordService.findByPayOrderNumber(payOrderNum);
        if (Objects.isNull(recordDTO)){
            throw new CustomException(ApiCode.PAY_CMB_ORDER_NOT_EXIST);
        }
        // 更新订单记录状态
        ddwxPaymentRecordService.updateById(new DdwxPaymentRecordDTO(recordDTO.getId(), CmbPayStatusEnums.succeeded.getCode(), TimeUtils.getNow()));
        // 推送时间
        LocalDateTime pushTime = TimeUtils.getNow();
        int pushStatus = CmbPayStatusEnums.pending.getCode();
        // 发送通知推送
        Result result = new Result(ApiCode.CMB,JacksonUtil.parse(noticeParams.getBodyStr(),Map.class));
        String noticeBodyJsonStr = JsonUtils.toJson(result);
        //增加签名信息
        noticeBodyJsonStr = addRequestSignature(noticeBodyJsonStr);
        String systemPlatform =(String) noticeParams.getAttrs().get("systemPlatform");
        DdwxPaymentCfgInfoDTO cfgInfo = ddwxPaymentCfgInfoService.queryInfoByBizCodeAndPlatform(phpCallbackBizCode,systemPlatform);
        String notifyUrl = cfgInfo.getNotifyUrl();
        log.info(noticeBodyJsonStr);
        // 实体类转换为Map
        //Map map = JSON.parseObject(JSON.toJSONString(student), Map.class);
        try {
            String resultMsg = HttpClientUtil.postJSON(notifyUrl, null, noticeBodyJsonStr);
            log.info("cmb notify result：{}", resultMsg);
            // 转义结果
            Result rts = JacksonUtil.parse(resultMsg, Result.class);
            if (Objects.nonNull(rts) && rts.getCode() == ApiCode.OK.getCode().intValue()) {
                pushStatus = CmbPayStatusEnums.succeeded.getCode();
            } else {
                pushStatus = CmbPayStatusEnums.failed.getCode();
            }
        } catch (Exception ex) {
            log.error("招商YQN03010支付回调异常", ex);
            pushStatus = CmbPayStatusEnums.failed.getCode();
        } finally {
            // message update
            //TO-DO (String orderNo, int status, int pushStatus, LocalDateTime pushTime, String noticeBodyJsonStr)
            updateMessage(payOrderNum,CmbPayStatusEnums.succeeded.getCode(),pushStatus,pushTime,noticeParams.getBodyStr());
        }
        log.info("cmb payBack result：{}", noticeParams.getBodyStr());
    }

    @Override
    public String getEventType() {
        return EventTypeEnums.YQN03010.getType();
    }

}
